<template>
  <div class="setting-container">
    <div class="app-container">
      <el-card border>
        <el-tabs>
          <!-- 左侧 -->
          <el-tab-pane label="角色管理">
            <!-- 按钮 -->
            <el-button icon="el-icon-plus" size="small" type="primary" @click="showDialog = true">新增角色</el-button>
            <!-- 表格 -->
            <el-table v-loading="loading" :data="list" border>
              <!-- 这里是通过element组件库中提供的type="index"属性来实现序号 -->
              <el-table-column label="序号" width="120" type="index" :index="handleIndex" />
              <el-table-column label="角色名称" width="240" prop="name" />
              <el-table-column label="描述" prop="description" />
              <el-table-column label="操作">
                <!-- 从这个组件里面获取这个组件的值 -->
                <template #default="{ row }">
                  <el-button size="small" type="success" @click="handleAuth(row.id)">分配权限</el-button>
                  <el-button size="small" type="primary" @click="handleEdit(row.id)">编辑</el-button>
                  <!-- 点击删除的时候获取这个数据的id的值 -->
                  <el-button size="small" type="danger" @click="delRole(row.id)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
          </el-tab-pane>

          <el-tab-pane label="公司信息">
            <!-- 公司信息 -->
          </el-tab-pane>
        </el-tabs>
        <!-- 表格分页 -->
        <!-- page-size表示每页显示几条数据
        page-sizes可以选择的每页条数列表
        ->箭头就是控制布局在左边还是在右边，箭头之左侧显示在左边，箭头的右边的内容显示到右边
        slot就是插槽，将el-pagination标签设置为双标签，双标签夹着的内容就是slot的功能，内容的位置在哪，slot就需要放在layout的哪个位置-->
        <el-pagination
          :page-size="fillterParams.pagesize"
          layout=" sizes, prev, pager, next, jumper,->,total"
          :total="total"
          :page-sizes="pagesizes"
          @current-change="changePage"
          @size-change="changeSize"
        />
      </el-card>
      <!-- 弹框 -->
      <el-dialog :title="title" :visible="showDialog" @close="btnCancel">
        <el-form ref="roleForm" :model="form" :rules="rules" label-width="100px">
          <el-form-item label="角色名称" prop="name">
            <el-input v-model="form.name" placeholder="请输入角色名称" />
          </el-form-item>
          <el-form-item label="角色描述">
            <el-input v-model="form.description" placeholder="请输入角色描述" />
          </el-form-item>
        </el-form>

        <template #footer>
          <el-button @click="btnCancel">取消</el-button>
          <el-button type="primary" @click="handleAdd">确认</el-button>
        </template>
      </el-dialog>
    </div>
    <!-- 分配权限的弹层 -->
    <el-dialog title="分配权限" :visible.sync="showAuthDialog" @open="loadAuthList">
      <div>
        权限列表
        <!-- - data 表示树的所有数据
- props 设置节点显示的数据名称
- show-checkbox 显示复选框
- node-key 设置数据节点的唯一表示的属性
- :default-checked-keys="[5, 10]"表示id是5和10的节点被选中,这个就是默认谁被选中
- default-expand-all 默认展开
- check-strictly  设置true, 可以关闭父子关联(父级节点可以单独选择) -->
        <el-tree
          ref="tree"
          v-loading="treeLoading"
          :data="authList"
          :props="defaultProps"
          :default-expand-all="true"
          :default-checked-keys="oldAuthList"
          :show-checkbox="true"
          :check-strictly="true"
          node-key="id"
        />
      </div>
      <template #footer>
        <div style="text-align: right">
          <el-button @click="showAuthDialog = false">取消</el-button>
          <el-button type="primary" @click="handleAuthSubmite">确定</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script>
import {
  reqGetRoleList,
  reqDeleteRole,
  reqAddRole,
  reqGetRoleDetail,
  reqUpdateRole,
  reqAssignPerm
} from '@/api/setting.js'

import { translateListToTree } from '@/utils'
import { reqGetPermissionList } from '@/api/permisson'

export default {
  name: 'Setting',
  data() {
    return {
      // 设置树形节点的属性名称
      defaultProps: { label: 'name' },
      treeLoading: false,
      // 已经拥有的权限的列表
      oldAuthList: [], // 存储已选中的权限id列表
      // 记录正在操作的角色
      roleId: '',
      // 分配权限的标志位
      showAuthDialog: false,
      authList: [], // 存储权限数据
      // 控制弹框的状态
      showDialog: false,
      // 添加loading效果
      loading: false,
      // 需要传输的查询参数
      pagesizes: [5, 10, 20, 30],
      fillterParams: {
        // 当前查询第几页
        page: 1,
        // 每页查询几条
        pagesize: 5
      },
      // 角色列表
      // 当前页的数据，这个数据每次加载都是覆盖的
      list: [],
      // 角色列表的总数
      total: 0,
      // 弹框中的表单内容
      form: {
        id: '',
        name: '',
        description: ''
      },
      // 表单中的验证规则
      rules: {
        name: [{ required: true, message: '请输入角色名称', trigger: ['blur', 'change'] }]
      }
    }
  },
  // 通过计算属性计算标题
  computed: {
    title() {
      return this.form.id ? '编辑角色' : '添加角色'
    }
  },
  created() {
    this.loadRoleList()
  },
  methods: {
    // 获取所有角色列表
    async loadRoleList() {
      try {
        // 设置loading的状态
        this.loading = true
        const ret = await reqGetRoleList(this.fillterParams)
        // console.log(ret)
        // 获取后判断是否获取成功
        if (ret.code === 10000) {
          // 获取成功
          // 将数据转存到data中的list中
          this.list = ret.data.rows
          this.total = ret.data.total
        } else {
          this.$message.error('获取角色列表失败')
        }
      } catch {
        this.$message.error('获取角色列表失败')
      } finally {
        // 获取loading状态
        this.loading = false
      }
    },
    // 监听每页条数的变化
    changeSize(size) {
      // 更新请求参数中的每页的条数，重新调用接口即可
      this.fillterParams.pagesize = size
      console.log(size)
      this.loadRoleList()
    },
    // 监听页码的切换,拿到的形参是最新的页面
    changePage(page) {
      // page表示当前页码，更新接口参数中的页面，重新调用接口。
      // 分页的逻辑就是页面中显示的条数
      this.fillterParams.page = page
      // console.log(`每页${page}条`)
      this.loadRoleList()
    },
    // 动态控制索引
    handleIndex(index) {
      // 形参index表示列表数据的索引，从0开始
      // 动态计算累加的索引
      // (当前页码 - 1) * 每页的条数
      // 当前页前面的页数*每页条数+index
      const { page, pagesize } = this.fillterParams
      return (page - 1) * pagesize + 1 + index
    },
    // 删除功能的实现
    async delRole(id) {
      // 删除之前先设置弹窗询问
      const ret = await this.$confirm('确认要删除角色吗？, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(err => err)
      // 点击取消
      if (ret === 'cancel') return
      // 点击确定
      try {
        const retDel = await reqDeleteRole(id)
        console.log(retDel)
        if (retDel.code === 10000) {
          // 删除成功后重新渲染列表
          // 如果当前页面数据被删完了，刷新上一页数据
          if (this.fillterParams.page > 1 && this.list.length === 1) {
            // 页面要大于1，且当前也就剩一条数据
            this.fillterParams.page -= 1
            // this.loadRoleList()
          }
          this.loadRoleList()
        } else {
          this.$message.error('删除角色失败')
        }
      } catch {
        this.$message.error('删除角色失败')
      }
    },
    // 添加角色的功能
    // 点击对话框确定的时候要做的事情
    async handleAdd() {
      this.handleSubmit()
    },
    // 点击取消要做的事
    btnCancel() {
      // 1.关闭对话框
      this.showDialog = false
      // 重置表单
      // 这句是获取data中的原始数据，将原始数据赋值给form,这里只需要form所以data后面就需要.form
      // this.form = this.$options.data().form
      // 这里重置表单的方法依赖于表单验证
      this.$refs.roleForm.resetFields()
      this.form.id = ''
      this.form.name = ''
      this.form.description = ''
    },
    // 实现编辑功能
    // 通过插槽获取了id，然后将id传输给后台，后台根据id返回结果
    // 点击编辑回填表单显示弹窗
    async handleEdit(id) {
      try {
        const ret = await reqGetRoleDetail(id)
        // console.log(ret)
        if (ret.code === 10000) {
          // 调接口成功将数据进行回填，并显示弹窗
          this.form.id = ret.data.id
          this.form.name = ret.data.name
          this.form.description = ret.data.description
          // 显示弹窗
          this.showDialog = true
          console.log(this.form)
        } else {
          this.$message.error('获取角色信息失败')
        }
      } catch {
        this.$message.error('获取数据失败')
      }
    },
    // 编辑完成
    async handleSubmit() {
      // 判断，如果form中存在id且不为空，就是编辑角色，否则就是添加角色
      if (this.form.id !== '') {
        // 编辑角色
        try {
          const ret = await reqUpdateRole(this.form)
          console.log(ret)
          if (ret.code === 10000) {
            // 说明编辑成功

            this.loadRoleList()
            this.showDialog = false
            // this.form.id = ''
            // this.form.name = ''
            // this.form.description = ''

            // this.$refs.roleForm.resetFields()
            this.btnCancel()
          } else {
            this.$message.error('编辑角色失败')
          }
        } catch {
          this.$message.error('编辑角色失败')
        }
      } else {
        // 这里有个小问题,当先点击了编辑后再点击添加就会有回填的现象
        // 添加角色
        try {
          // 调接口传数据
          const ret = await reqAddRole(this.form)
          // console.log(ret)
          if (ret.code === 10000) {
            // 说明请求数据成功
            // 1.重新渲染数据

            this.loadRoleList()
            // 2.关闭弹窗
            // this.showDialog = false
            // 可以直接调用点击取消的时候
            this.btnCancel()
          } else {
            this.$message.error('添加角色失败')
          }
        } catch {
          this.$message.error('添加角色失败')
        }
      }
    },
    // 给指定角色进行授权
    handleAuth(id) {
      // 将分配的谁记录下来
      this.roleId = id
      // 打开弹窗
      this.showAuthDialog = true
    },
    // 分配权限的弹窗打开后触发了open事件
    // async loadAuthList() {
    //   // 加载角色的权限数据
    //   try {
    //     const ret = await reqGetPermissionList()
    //     if (ret.code === 10000) {
    //       // 请求数据成功
    //       // 1.将数据存储到data的authList中
    //       // this.permissionData = ret.data(原本需要这样写，但是获取的数据是一位的扁平的数据，所以需要转换称为树形结构)
    //       // 2.将数据转换成为树形结构
    //       this.authList = translateListToTree(ret.data, '0')
    //       console.log(this.authList)
    //     } else {
    //       this.$message.error('获取角色权限失败')
    //     }
    //   } catch {
    //     this.$message.error('获取角色权限失败')
    //   }
    //   try {
    //     const auths = await reqGetRoleDetail(this.roleId)
    //     console.log(auths)
    //     this.oldAuthList = auths.data.permIds
    //   } catch {
    //     this.$message.error('获取信息失败')
    //   }
    // },
    // ########################################################
    // // 优化的写法
    loadAuthList() {
      // 获取了所有的权限
      const ret = reqGetPermissionList()
      // 获取已经选中的权限,用来进行数据回填
      const auths = reqGetRoleDetail(this.roleId)
      console.log(auths)
      // 通过Promise中的all方法来一起判断，让串行的变为并行的，这样就不用等待，增加效率
      // 点击分配权限的弹框的确定的时候
      Promise.all([ret, auths])
        .then(results => {
          this.authList = translateListToTree(results[0].data, '0')
          // 这是将数据进行回填，通过的是树形结构中的   :default-checked-keys="oldAuthList"这个属性，这个属性绑定的数组就是需要回填的数据的id的数组
          // 方法一的代码
          this.oldAuthList = results[1].data.permIds
          // 还有第二种数据回填的方法就是使用树形结构的ref属性，使用它的ref属性的时候需要用到setCheckedKeys这个方法，里面放的是需要回填的数据的id
          // this.$refs.tree.setCheckedKeys(results[1].data.permIds)
        })
        .catch(err => {
          console.log(err)
          this.$message.error('获取权限信息失败')
        })
    },
    // 控制分配权限提交表单
    async handleAuthSubmite() {
      try {
        // 需要角色id以及当前选中的所有结点的id

        const ret = await reqAssignPerm({
          // id:当前分配权限的角色id
          id: this.roleId,
          // 当前选中的所有的权限的id
          permIds: this.$refs.tree.getCheckedKeys()
        })
        if (ret.code === 10000) {
          // 授权成功，关闭弹窗清
          this.showAuthDialog = false
          // this.$refs.tree.setCheckedkeys([])
          // this.authList = []
          this.$message.success('分配权限成功')
        } else {
          this.$message.error('分配权限失败')
        }
      } catch {
        this.$message.error('分配权限失败')
      }
    }
  }
}
</script>
